#include "common/elements/state.h"

#include "common/log/log.h"

#include "data_state.h"

namespace Database
{

DataState::DataState(Elements::Element* element)
{
    setElement(element);
}

DataState::DataState(std::shared_ptr<Elements::Element> element)
{
    m_element = element;
}

DataState::DataState(sqlite::database& database, unsigned id)
{
    fromDatabase(database, id);
}

DataElement* DataState::clone() const
{
    if (m_element)
        return new DataState(m_element->clone());

    return nullptr;
}

DataElement* DataState::wrap(Elements::Element* element) const
{
    return new DataState(element);
}

void DataState::toDatabase(sqlite::database& database)
{
    const auto element = std::dynamic_pointer_cast<Elements::State>(m_element);
    if (nullptr == element)
        return;

    if (0 == element->id())
    {
        const auto sqlStr = "INSERT INTO State "
                            "( caption "
                            ", description "
                            ", workflowId "
                            ", weight "
                            ", orderNumber "
                            ", isArchive "
                            ", isQueue "
                            ") VALUES (?,?,?,?,?,?,?);";
        database
            << sqlStr
            << element->caption()
            << element->description()
            << element->workflowId()
            << element->weight()
            << element->orderNumber()
            << element->isArchive()
            << element->isQueue();
        element->setId(lastAddedId(database));
        return;
    }

    const auto sqlStr = "INSERT OR REPLACE INTO State "
                        "( id "
                        ", caption "
                        ", description "
                        ", workflowId "
                        ", weight "
                        ", orderNumber "
                        ", isArchive "
                        ", isQueue "
                        ") VALUES (?,?,?,?,?,?,?,?);";
    database
        << sqlStr
        << element->id()
        << element->caption()
        << element->description()
        << element->workflowId()
        << element->weight()
        << element->orderNumber()
        << element->isArchive()
        << element->isQueue();
}

void DataState::fromDatabase(sqlite::database& database, unsigned id)
{
    if (nullptr == m_element)
        m_element.reset(new Elements::State());

    const auto element = std::dynamic_pointer_cast<Elements::State>(m_element);

    const auto sqlStr = "SELECT "
                        "  id "
                        ", caption "
                        ", description "
                        ", workflowId "
                        ", weight "
                        ", orderNumber "
                        ", isArchive "
                        ", isQueue "
                        "FROM State WHERE id = ?;";
    database << sqlStr << id >>
        [element](
            unsigned id,
            std::string caption,
            std::string description,
            unsigned workflowId,
            unsigned weight,
            unsigned orderNumber,
            bool isArchive,
            bool isQueue
        )
    {
        element->setId(id);
        element->setCaption(caption);
        element->setDescription(description);
        element->setWorkflowId(workflowId);
        element->setWeight(weight);
        element->setOrderNumber(orderNumber);
        element->setIsArchive(isArchive);
        element->setIsQueue(isQueue);
    };
}

std::vector<Elements::Element*> DataState::fromDatabaseElements(
    sqlite::database& database,
    std::vector<unsigned> ids
) const
{
    const auto sqlStr = "SELECT "
                        "  id "
                        ", caption "
                        ", description "
                        ", workflowId "
                        ", weight "
                        ", orderNumber "
                        ", isArchive "
                        ", isQueue "
                        "FROM State WHERE id in ("
        + questionMarks(ids.size())
        + ")";

    auto query = database << sqlStr;
    for (auto id : ids)
        query << id;

    std::vector<Elements::Element*> result;
    query >>
        [&result](
            unsigned id,
            std::string caption,
            std::string description,
            unsigned workflowId,
            unsigned weight,
            unsigned orderNumber,
            bool isArchive,
            bool isQueue
        )
    {
        auto element = new Elements::State();
        element->setId(id);
        element->setCaption(caption);
        element->setDescription(description);
        element->setWorkflowId(workflowId);
        element->setWeight(weight);
        element->setOrderNumber(orderNumber);
        element->setIsArchive(isArchive);
        element->setIsQueue(isQueue);
        result.push_back(element);
    };
    return result;
}

// Получение идентификаторов ---------------------------------------------------

std::vector<unsigned> DataState::ids(
    sqlite::database& database
)
{
    std::vector<unsigned> result;
    database << "SELECT id FROM State;"
        >> [&result](unsigned id)
    {
        result.emplace_back(id);
    };
    return result;
}

// Удаление --------------------------------------------------------------------

void DataState::removeOne(
    sqlite::database& database,
    unsigned id
)
{
    std::vector<unsigned> ids = { id };
    remove(database, ids);
}

void DataState::remove(
    sqlite::database& database,
    std::vector<unsigned> ids
)
{
    const auto sqlStr = "DELETE FROM State WHERE id in ("
        + questionMarks(ids.size())
        + ")";

    auto query = database << sqlStr;
    for (auto id : ids)
        query << id;

    query.execute();
    query.reset();
}

} // namespace Elements
